﻿using System;
using System.Linq;
using System.Linq.Expressions;
using Castle.MonoRail.Framework;
using Castle.MonoRail.Framework.Filters;
using Castle.MonoRail.Framework.Helpers;
using StateTheater.Models;
using StateTheaterDataModel;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Web;
using System.Security.Principal;

namespace StateTheater.Controllers
{
	[Layout("default"), Rescue("generalerror")]
	[Filter(ExecuteWhen.BeforeAction, typeof(MobileFilter))]
	public class TroupeController : SmartDispatcherController
	{
		readonly Status OK = new Status("OK");
		readonly Status BAD = new Status("BAD");
		const string PhotoFormat = "troupe-{0}.jpg";

		StateTheaterDataContext db;
		public TroupeController(StateTheaterDataContext db)
		{
			this.db = db;
		}

		public void Display(int id)
		{
			Display(tr => tr.TroupeID == id);
		}
		public void Display(string name)
		{
			Display(tr => tr.shortname == name);
		}
		void Display(Expression<Func<Troupe, bool>> whereClause)
		{
			var troupe = (from tr in db.Troupes.Where(whereClause)
					select new    TroupeDetail
					{
						active = tr.active,
						TroupeID = tr.TroupeID,
						BoxOfficePhone = tr.BoxOfficePhone,
						BusinessPhone = tr.BusinessPhone,
						Comments = tr.Comments,
						Email = tr.Email,
						FaxPhone = String.IsNullOrEmpty(tr.FaxPhone) ? null: tr.FaxPhone,
						HasMembers = tr.HasMembers,
						Logo = tr.Logo,
						LogoOnly = tr.LogoOnly,
						MailingAddress = tr.MailingAddress,
						Name = Util.AdjTitle(tr.Name),
						Shortname= tr.shortname,
						SeasonEnd = tr.SeasonEnd.Value,
						SeasonStart = tr.SeasonStart,
						VenueID = tr.VenueID.HasValue ? tr.VenueID.Value : 0,
						VenueName = tr.VenueID.HasValue ?  Util.AdjTitle(tr.Venue.Name) : "",
						WWWSite = tr.WWWSite
					}).SingleOrDefault();

			if (!String.IsNullOrEmpty(troupe.WWWSite) && troupe.WWWSite.StartsWith("http://"))
				PropertyBag["WWWSite"] = troupe.WWWSite.Substring(7);
			else
				PropertyBag["WWWSite"] = troupe.WWWSite;


			PropertyBag["Troupe"] = troupe;
			PropertyBag["phoneformatter"] = new PhoneFormatter();
			PropertyBag["MailingAddress"] = (troupe.MailingAddress ?? "").Replace("\n", "<br />");
			if (troupe.Email != null)
			PropertyBag["EncodedEmail"] = Util.Encode(troupe.Email);


			int id = troupe.TroupeID;
			int currentYear = DateTime.Now.Year;
			DateTime SeasonStart = new DateTime(currentYear, troupe.SeasonStart, 1);
			if (SeasonStart > DateTime.Today)
				SeasonStart = SeasonStart.AddYears(-1);
			DateTime SeasonEnd = SeasonStart.AddYears(1).AddDays(-1);

			PropertyBag["Assocs"] = db.Associations.Where(a => a.TroupeID == id).Select(a => a.Organization.Trim()).ToArray();

			var prods = from pr in db.Productions
						where pr.TroupeID == id
						&& pr.FirstPerformance >= SeasonStart
						&& pr.FirstPerformance < SeasonEnd
						orderby pr.FirstPerformance, pr.FlowerID
						select new ShowLine
						{
							Title = pr.Play.Title,
							ProductionID = pr.ProductionID,
							AnthologyFlag = pr.AnthologyFlag,
							FlowerID = pr.FlowerID.HasValue ? pr.FlowerID.Value : 0,
							FirstPerformance = pr.FirstPerformance,
							LastPerformance = pr.LastPerformance.HasValue ? pr.LastPerformance.Value : pr.FirstPerformance
						};
			var Season = prods.ToList();
			PropertyBag["Season"] = Season;

			string user = this.Context.CurrentUser.Identity.Name;
			bool isAdmin = this.Context.CurrentUser.IsInRole("Admin");
			if (isAdmin || db.TroupePermissions.Any(tp=> tp.FORUM_MEMBER.M_NAME== user && tp.Troupeid == id))
			{
				PropertyBag["allowEdit"] = true;
			}
		}

		public void AllShows(string name)
		{
			var troupe = (from tr in db.Troupes.Where(t => t.shortname == name)
						  select new  
						  {
							  TroupeID = tr.TroupeID,
							  Name = tr.Name,
							  shortname = tr.shortname,
							  SeasonEnd = tr.SeasonEnd.Value,
							  SeasonStart = tr.SeasonStart,
						  }).SingleOrDefault();

			PropertyBag["Troupe"] = troupe;

			var prods = from pr in db.Productions
						where pr.TroupeID == troupe.TroupeID
						orderby pr.FirstPerformance descending, (pr.AnthologyFlag ? -1 : 1),  pr.FlowerID
						select new ShowLine
						{
							Title = pr.Play.Title,
							ProductionID = pr.ProductionID,
							AnthologyFlag = pr.AnthologyFlag,
							FlowerID = pr.FlowerID.HasValue ? pr.FlowerID.Value : 0,
							FirstPerformance = pr.FirstPerformance,
							LastPerformance = pr.LastPerformance.HasValue ? pr.LastPerformance.Value : pr.FirstPerformance
						};
			var Season = prods.ToList();
			PropertyBag["Seasons"] = Season;
		}

		public void ListAll()
		{
			var q = (from T in db.Troupes
					 orderby T.Name
					 select new TroupeDetailShort
					 {
						 Name = T.Name,
						 FirstLetter = T.Name[0],
						 Shortname = T.shortname,
						 Active = T.active,
						 TroupeID = T.TroupeID,
						 VenueID = T.VenueID,
						 VenueName = T.Venue.Name
					 })
					.ToList();
			q.ForEach(t => t.Name = Util.AdjTitle(t.Name));
			PropertyBag["Troupes"] = q;
		}

		public void Find()
		{
		}

		class CountyList
		{
			public string Name { get; set; }
			public string Shortname { get; set; }
			public string VenueName { get; set; }
			public string City { get; set; }
			public int VenueID { get; set; }
			public string Address { get; set; }
			public string Lat { get; set; }
			public string Long { get; set; }
		}
		public void ByCounty(string name)
		{
			var q = (from l in db.Locations
					 from t in db.Troupes
					 where l.County1.Name == name && t.Venue.ZipCode == l.ZipCode && t.active
					 orderby t.Venue.City
					 select new CountyList
					 {
						 Name = Util.AdjTitle(t.Name),
						 Shortname = t.shortname,
						 VenueName = Util.AdjTitle(t.Venue.Name),
						 City = t.Venue.City,
						 VenueID = t.VenueID.Value,
						 Address  =( t.Venue.Address2 ?? t.Venue.Address1 )+ ", " + t.Venue.City + "," + t.Venue.State + " " + t.Venue.ZipCode,
						 Lat = t.Venue.lat.HasValue ? t.Venue.lat.ToString() : "null",
						 Long = t.Venue.lng.HasValue ? t.Venue.lng.ToString() : "null"
					 }).ToList();

			PropertyBag["troupes"] = q;
			PropertyBag["county"] = name;
		}

			class DistanceListing
			{
				public LatLong latlong {get; set;}
				public string TroupeName {get; set;}
				public string shortname {get; set;}
				public string VenueName {get; set;}
				public int VenueID {get; set;}
				public string City {get; set;}
				public double Distance {get; set;}
				public string strDistance { get; set; }
				public string Heading { get; set; }
			};

		public void ByDistance(string zip)
		{
			var StartLoc = (from loc in db.Locations
					 where loc.ZipCode == zip
					 select new LatLong
					 {
						 Lat = loc.Lat,
						 Long = loc.Long
					 }).SingleOrDefault();

			PropertyBag["Zipcode"] = zip;

			if (StartLoc == null)
			{
			}
			else
			{
				var troupes  = (from tr in db.Troupes
						 where tr.active && tr.Venue.Location != null
						 select new DistanceListing
						 {
							 latlong = new LatLong
							 {
								 Lat = tr.Venue.lat ?? tr.Venue.Location.Lat,
								 Long = tr.Venue.lng ?? tr.Venue.Location.Long,
							 },
							 TroupeName = tr.Name,
							 shortname = tr.shortname,
							 VenueName = tr.Venue.Name,
							 VenueID = tr.VenueID.Value,
							 City = tr.Venue.City
						 }).ToList();

				foreach (DistanceListing dl in troupes)
				{
					dl.Distance = Distance.mileDist(StartLoc, dl.latlong);
					dl.Heading = Distance.arrowImgForHdg(Distance.Heading(StartLoc, dl.latlong));
					dl.strDistance = dl.Distance.ToString("##0.00");
					dl.TroupeName = Util.AdjTitle(dl.TroupeName);
					dl.VenueName = Util.AdjTitle(dl.VenueName);
				}

				troupes.Sort( (lhs, rhs) => {return lhs.Distance.CompareTo(rhs.Distance);});

				PropertyBag["Troupes"] = troupes;
			}
		}

		public void Edit(int id)
		{
			var troupe = db.Troupes.First(t => t.TroupeID == id);
			PropertyBag["troupe"] = troupe;
			PropertyBag["assocs"] = troupe.Associations.Select(a=>a.Organization.Trim()).ToList();
			AdminController.GetCounties(PropertyBag, db);

			PropertyBag["Organizations"] = db.Organizations.ToArray();

		}

		public void New()
		{
			PropertyBag["troupe"] = new Troupe();
			AdminController.GetCounties(PropertyBag, db);
			RenderView("edit");
		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public Status Save([DataBind("troupe")] Troupe troupe)
		{
			Troupe curr = null;
			string[] assoc = BindObject<string[]>("assoc");
			if ((troupe.TroupeID != 0))
			{
				curr = db.Troupes.FirstOrDefault(tr => tr.TroupeID == troupe.TroupeID);
				PropertyBag["action"] = "updated";
//                if (curr.Name != troupe.Name)
//                {
////					var oldfile = Util.SEOEscape(curr.Name, false);
////					var newfile = Util.SEOEscape(troupe.Name, false);
////					var oldpath = Path.Combine(HttpContext.Server.MapPath(@"~/content/images/logos"), oldfile);
////					var newpath = Path.Combine(HttpContext.Server.MapPath(@"~/content/images/upload"), newfile);
//                }

					curr.Associations.ToList().ForEach(a => db.Associations.DeleteOnSubmit(a));
					db.SubmitChanges();
			}
			else
			{
				curr = new Troupe();
				db.Troupes.InsertOnSubmit(curr);
				PropertyBag["action"] = "added";
			}

			curr.active = troupe.active;
			curr.BoxOfficePhone = troupe.BoxOfficePhone;
			curr.BusinessPhone = troupe.BusinessPhone;
			curr.Comments = troupe.Comments;
			curr.Contact = troupe.Contact;
			curr.ContactPhone = troupe.ContactPhone;
			curr.Email = troupe.Email;
			curr.FaxPhone = troupe.FaxPhone;
			curr.LogoOnly = troupe.LogoOnly;
			curr.MailingAddress = troupe.MailingAddress;
			curr.Name = troupe.Name;
			/*
			curr.NJTA = troupe.NJTA;
			curr.NJTL = troupe.NJTL;
			curr.RECT = troupe.RECT;
			 */

			foreach (var a in assoc)
			{
				curr.Associations.Add(new Association() { Organization = a, TroupeID = troupe.TroupeID });
			}

			curr.SeasonStart = troupe.SeasonStart;
			curr.SeasonEnd = troupe.SeasonStart == 1 ? 12 : troupe.SeasonStart -1;
			curr.shortname = troupe.shortname;
			curr.WWWSite = troupe.WWWSite;
			curr.VenueID = troupe.VenueID;
			curr.ModTime = DateTime.Now;
			curr.ModUser = WindowsIdentity.GetCurrent().Name;

			db.SubmitChanges();

			PropertyBag["troupe"] = curr;
			AdminController.RecordUserAction(db, this, "edittroupe", curr.TroupeID, PropertyBag);

			return OK;
		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public Status UniqueShortnameJson(int id, string name)
		{
			if (!name.All(Char.IsLetterOrDigit))
				return new Status("Error - Bad Format (no space or punctuation allowed");

			Troupe t = db.Troupes.FirstOrDefault(tr => tr.shortname == name);
			return t == null || t.TroupeID == id ? OK : new Status("Error- Short Name already in use");
		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public Status RemoveLogo(int id)
		{
			var curr = db.Troupes.FirstOrDefault(tr => tr.TroupeID == id);
			if (curr != null)
			{
				curr.Logo = null;
				curr.LogoOnly = false;
				db.SubmitChanges();
			}
			return OK;
		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public Status UploadLogo(HttpPostedFile uploadedPhoto, int troupe_TroupeID)
		{
			try
			{
				var curr = db.Troupes.FirstOrDefault(tr => tr.TroupeID == troupe_TroupeID);
				if (curr != null)
				{
					var photo = new Bitmap(uploadedPhoto.InputStream);
					photo = Util.ResizeImage(photo, 700, 350);

					var filename = Util.SEOEscape(curr.Name, false) + ".jpg";

					photo.Save(Path.Combine(HttpContext.Server.MapPath(@"~/content/images/upload"), filename), ImageFormat.Jpeg);
					if ( ! String.IsNullOrEmpty(curr.Logo))
					{
						// Might throw if filename is invalid (won't throw if didn't exist)
						File.Delete(Path.Combine(HttpContext.Server.MapPath(@"~/content/images/logos"), curr.Logo));
					}

					File.Copy(Path.Combine(HttpContext.Server.MapPath(@"~/content/images/upload"), filename),
						Path.Combine(HttpContext.Server.MapPath(@"~/content/images/logos"), filename),
						true);

						File.Delete(Path.Combine(HttpContext.Server.MapPath(@"~/content/images/upload"), filename));

					curr.Logo = filename;
					db.SubmitChanges();
					RenderText("{{'status':'OK', 'filename':'{0}'}}", filename);
					return OK;
				}
			}
			catch (Exception ex)
			{
				HttpContext.Response.StatusCode = 500;
				HttpContext.Response.StatusDescription = ex.Message;
			}

			return BAD;
		}
	}
}
